﻿using System.Net.Sockets;
using Microsoft.Extensions.Options;
using NModbus;
using qYun.ApiService.Models;
using PlcModel=qYun.Shared.Models.PlcModel;

namespace qYun.ApiService.Services;

/// <summary>
/// plc通讯服务
/// </summary>
public class PlcService:IPlcService
{
    public required TcpClient _client;
    public required SystemConfig _config;
    private ILogger<PlcService> _logger;
    public required IModbusMaster _master;

    /// <summary>
    /// PlsService构造函数
    /// </summary>
    /// <param name="logger"></param>
    /// <param name="config"></param>
    public PlcService(ILogger<PlcService> logger,IOptions<SystemConfig> config)
    {
        _logger = logger;
        _config = config.Value;
        var plcIp = _config.PLC?.DeviceIp;
        var plcPort = _config.PLC?.DevicePort;
        if (plcIp == null||plcPort==null)
        {
            _logger.LogError("PLC配置错误，请检查配置文件");
            return;
        }
        //_client = new TcpClient(plcIp, int.Parse(plcPort));
        //_master = new ModbusFactory().CreateMaster(_client);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="startAddress"></param>
    /// <param name="length"></param>
    /// <returns></returns>
    public async Task<ushort[]> ReadHoldingRegisterAsync(ushort startAddress,ushort length)
    {
        try
        {
            var result = await _master.ReadHoldingRegistersAsync(0x01, startAddress, length);
            return result.ToArray();
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    public async Task<PlcModel> GetDataAsync()
    {
        var model = new PlcModel();

                // 数据处理解析

                // Addr_43
                var res = await ReadHoldingRegisterAsync(43, 1);
                model.VacuumPumpRunning = Convert.ToBoolean(res[0] & 0x0001);
                model.RootsPumpRunning = Convert.ToBoolean(res[0] & 0x0002);
                model.InletPumpRunning = Convert.ToBoolean(res[0] & 0x0004);
                model.OutletPumpRunning = Convert.ToBoolean(res[0] & 0x0008);

                model.MainSolenoidValveRunning = Convert.ToBoolean(res[0] & 0x0010);
                model.Heater1Running = Convert.ToBoolean(res[0] & 0x0020);
                model.Heater2Running = Convert.ToBoolean(res[0] & 0x0040);
                model.Heater3Running = Convert.ToBoolean(res[0] & 0x0080);

                model.Heater4Running = Convert.ToBoolean(res[0] & 0x0100);
                model.BypassSolenoidValveRunning = Convert.ToBoolean(res[0] & 0x0200);
                model.InletSolenoidValve = Convert.ToBoolean(res[0] & 0x0400);
                model.AutoRun = Convert.ToBoolean(res[0] & 0x0800);

                model.OilInjectionRunning = Convert.ToBoolean(res[0] & 0x1000);
                model.OilDischargeRunning = Convert.ToBoolean(res[0] & 0x2000);
                model.VacuumRunning = Convert.ToBoolean(res[0] & 0x4000);
                model.DeviceRunning = Convert.ToBoolean(res[0] & 0x8000);

                // Addr_41
                res = await ReadHoldingRegisterAsync(41, 1);
                model.EmergencyStopPressed = Convert.ToBoolean(res[0] & 0x0001);
                model.PhaseSequenceAlarm = Convert.ToBoolean(res[0] & 0x0002);
                model.VacuumOrRootsPumpOverload = Convert.ToBoolean(res[0] & 0x0004);
                model.InletPumpOverload = Convert.ToBoolean(res[0] & 0x0008);

                model.InletInverterFault = Convert.ToBoolean(res[0] & 0x0010);
                model.OutletInverterFault = Convert.ToBoolean(res[0] & 0x0020);
                model.OutletPumpOverload = Convert.ToBoolean(res[0] & 0x0040);
                model.OutletPumpOverheat = Convert.ToBoolean(res[0] & 0x0080);

                model.OilPanFull = Convert.ToBoolean(res[0] & 0x0100);
                model.OilMistSeparatorOilStored = Convert.ToBoolean(res[0] & 0x0200);
                model.FirstGroupHeaterOverload = Convert.ToBoolean(res[0] & 0x0400);
                model.SecondGroupHeaterOverload = Convert.ToBoolean(res[0] & 0x0800);

                model.ThirdGroupHeaterOverload = Convert.ToBoolean(res[0] & 0x1000);
                model.FourthGroupHeaterOverload = Convert.ToBoolean(res[0] & 0x2000);
                model.BoxTemperatureHigh = Convert.ToBoolean(res[0] & 0x4000);
                model.FoamAlarm = Convert.ToBoolean(res[0] & 0x8000);

                // Addr_42
                res = await ReadHoldingRegisterAsync(42, 1);
                model.InletPumpPressureHighLowAlarm = Convert.ToBoolean(res[0] & 0x0001);
                model.InletPumpOutletPressureHighAlarm = Convert.ToBoolean(res[0] & 0x0002);
                model.InletPumpFlowSwitchAlarm = Convert.ToBoolean(res[0] & 0x0004);
                model.HeaterOutletTemperatureHigh = Convert.ToBoolean(res[0] & 0x0008);

                model.OutletPumpPressureHighAlarm = Convert.ToBoolean(res[0] & 0x0010);
                model.OutletPumpFlowSwitchAlarm = Convert.ToBoolean(res[0] & 0x0020);
                model.HighLiquidLevelAlarm = Convert.ToBoolean(res[0] & 0x0040);
                model.LowLiquidLevelAlarm = Convert.ToBoolean(res[0] & 0x0080);

                model.InletPressureDifferenceBlocked = Convert.ToBoolean(res[0] & 0x0100);
                model.OutletPressureDifferenceBlocked = Convert.ToBoolean(res[0] & 0x0200);

                model.DeviceAlarm = Convert.ToBoolean(res[0] & 0x2000);

                // Addr_37
                res = await ReadHoldingRegisterAsync(37, 1);
                model.CumulativeRunTimeMinutes = (short)res[0];

                // Addr_38
                res = await ReadHoldingRegisterAsync(38, 1);
                model.CumulativeRunTimeHours = (short)res[0];

                // Addr_39
                res = await ReadHoldingRegisterAsync(39, 1);
                model.CumulativeRunTimeDays = (short)res[0];

                // Addr_45
                res = await ReadHoldingRegisterAsync(45, 1);
                model.DeviceStatus = (short)res[0];

                // Addr_47
                res = await ReadHoldingRegisterAsync(47, 1);
                model.CurrentRunMinutes = (short)res[0];

                // Addr_48
                res = await ReadHoldingRegisterAsync(48, 1);
                model.CurrentRunHours = (short)res[0];

                // Addr_49
                res = await ReadHoldingRegisterAsync(49, 1);
                model.CurrentRunDays = (short)res[0];

                // Addr_180
                res = await ReadHoldingRegisterAsync(180, 1);
                model.InletFilterLife = (short)res[0];

                // Addr_181
                res = await ReadHoldingRegisterAsync(181, 1);
                model.OutletFilterLife = (short)res[0];

                // Addr_196
                res = await ReadHoldingRegisterAsync(196, 1);
                model.OutletPumpRunRate = (short)res[0];

                // Addr_198
                res = await ReadHoldingRegisterAsync(198, 1);
                model.InletPumpRunSpeed = (short)res[0];

                // Addr_200
                res = await ReadHoldingRegisterAsync(200, 1);
                model.PressurePT01 = ((short)res[0]) / 100.0f;

                // Addr_201
                res = await ReadHoldingRegisterAsync(201, 1);
                model.PressurePT02 = ((short)res[0]) / 100.0f;

                // Addr_202
                res = await ReadHoldingRegisterAsync(202, 1);
                model.PressurePT03 = ((short)res[0]) / 100.0f;

                // Addr_203
                res = await ReadHoldingRegisterAsync(203, 1);
                model.PressurePT04 = ((short)res[0]) / 100.0f;

                // Addr_204
                res = await ReadHoldingRegisterAsync(204, 1);
                model.PressurePT05 = ((short)res[0]) / 100.0f;

                // Addr_210
                res = await ReadHoldingRegisterAsync(210, 1);
                model.InletTemperatureTT01 = ((short)res[0]) / 10.0f;

                // Addr_211
                res = await ReadHoldingRegisterAsync(211, 1);
                model.OutletTemperatureTT02 = ((short)res[0]) / 10.0f;

                // Addr_212
                res = await ReadHoldingRegisterAsync(212, 1);
                model.HeaterOutletTemperatureTT03 = ((short)res[0]) / 10.0f;

                // Addr_213
                res = await ReadHoldingRegisterAsync(213, 1);
                model.HeaterProtectionTemperatureTT04 = ((short)res[0]) / 10.0f;

                // Addr_326
                res = await ReadHoldingRegisterAsync(326, 1);
                model.InletFlowMeterFT01 = (short)res[0];

                // Addr_327
                res = await ReadHoldingRegisterAsync(327, 1);
                model.OutletFlowMeterFT02 = (short)res[0];

                // Addr_218
                res = await ReadHoldingRegisterAsync(218, 1);
                model.InletFilter013PressureDifference = ((short)res[0]) / 100.0f;

                // Addr_219
                res = await ReadHoldingRegisterAsync(219, 1);
                model.OutletFilter010PressureDifference = ((short)res[0]) / 100.0f;

                // Addr_230
                res = await ReadHoldingRegisterAsync(230, 2);
                model.ContainerVacuumDPT01 = (int)(res[0] << 16 | res[1]);

                // Addr_232
                res = await ReadHoldingRegisterAsync(232, 2);
                model.TransformerVacuumDPT02 = (int)(res[0] << 16 | res[1]);
                
                return model;
    }
}

/// <summary>
/// PlcService的服务接口
/// </summary>
public interface IPlcService
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="startAddress"></param>
    /// <param name="length"></param>
    /// <returns></returns>
    public Task<ushort[]> ReadHoldingRegisterAsync(ushort startAddress,ushort length);

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    public Task<PlcModel> GetDataAsync();
}
